﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Rs.Common.Enum;

namespace Rs.Common.WepPost
{
    public class WebPostHelper
    {
        private static String ProxyAddress = ConfigurationManager.AppSettings["ProxyAddress"];
        private static String ProxyProt = ConfigurationManager.AppSettings["ProxyProt"];

        /// <summary>
        /// web后台提交
        /// </summary>
        /// <param name="ActionURL">提交地址</param>
        /// <param name="ActionMethod">执行动作POST,GET</param>
        /// <param name="ContentType">参数格式</param>
        /// <param name="FormData">提交数据</param>
        /// <param name="Charset">FormData编码字符集及可以接收结果的字符编码集</param>
        /// <param name="RPCTimeout">执行超时时间(毫秒)</param>
        /// <param name="Cookies"></param>
        /// <returns>执行结果信息</returns>
        private static WebPostResult WebPost(String ActionURL, EnumVerbs ActionMethod, String ContentType, byte[] FormData, EnumCharsetType Charset,
           Int32 RPCTimeout, CookieCollection Cookies = null, Dictionary<string, string> DicToken = null)
        {
            var CurrentEncoding = Encoding.GetEncoding((Int32)Charset);
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate;
                ServicePointManager.DefaultConnectionLimit = 2048;

                var m_httpwebrequest = (HttpWebRequest)WebRequest.Create(ActionURL);
                m_httpwebrequest.KeepAlive = false;
                m_httpwebrequest.Timeout = RPCTimeout;
                m_httpwebrequest.ProtocolVersion = HttpVersion.Version10;
                m_httpwebrequest.Headers.Add(HttpRequestHeader.ContentEncoding, HttpHelper.WinConvertToHttpCharset(Charset));
                m_httpwebrequest.Headers.Add(HttpRequestHeader.AcceptCharset, HttpHelper.WinConvertToHttpCharset(Charset));
                m_httpwebrequest.Headers.Add(HttpRequestHeader.AcceptEncoding, HttpHelper.GZipAcceptEncoding);
                if (DicToken != null)
                    foreach (var dic in DicToken)
                        m_httpwebrequest.Headers.Add(dic.Key, dic.Value);
                m_httpwebrequest.Method = ActionMethod.ToString();
                m_httpwebrequest.ContentType = ContentType;
                m_httpwebrequest.CookieContainer = new CookieContainer();

                if (Cookies != null)
                {
                    m_httpwebrequest.CookieContainer.Add(Cookies);
                }

                if (ActionURL.Substring(0, 5).ToLower() == "https")
                {
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
                }

                m_httpwebrequest.ContentLength = FormData == null ? 0 : FormData.Length;

                //在测试游伴伴对外接口时,发现Proxy置空则无法连接到接口服务器地址,不置空则可以连接
                //暂且注释
                // m_httpwebrequest.Proxy = null;

                var webProxy = CreateWebProxy();
                if (webProxy != null)
                {
                    m_httpwebrequest.Proxy = webProxy;
                }

                if (m_httpwebrequest.ContentLength > 0)
                {
                    using (var requeststream = m_httpwebrequest.GetRequestStream())
                    {
                        requeststream.Write(FormData, 0, FormData.Length);
                        requeststream.Flush();
                    }
                }

                using (var res = (HttpWebResponse)m_httpwebrequest.GetResponse())
                {
                    if (res.StatusCode > HttpStatusCode.OK)
                    {
                        return new WebPostResult(
                            false,
                            CurrentEncoding.GetBytes(String.Format("服务端响应状态码{0}", res.StatusCode)),
                            Charset,
                            String.Empty);
                    }

                    var stmMemory = new MemoryStream();
                    using (var s = res.GetResponseStream())
                    {
                        var buffer = new byte[4096];
                        int bytesRead;
                        //服务器不一定一次性发送所有数据,读到-1时可以认为已经没有数据
                        while ((bytesRead = s.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            stmMemory.Write(buffer, 0, bytesRead);
                        }
                    }
                    return new WebPostResult(
                            true,
                            stmMemory.ToArray(),
                        //如果Response中无字符集信息，默认使用Requese中字符集
                            !string.IsNullOrEmpty(res.CharacterSet)
                                ? HttpHelper.HttpConvertToWinCharset(res.CharacterSet)
                                : Charset,
                            res.ContentEncoding,
                            res);
                }
            }
            catch (Exception e)
            {
                return new WebPostResult(
                            false,
                            CurrentEncoding.GetBytes(e.ToString()),
                            Charset,
                            String.Empty);
            }
        }

        private static IWebProxy CreateWebProxy()
        {
            if (String.IsNullOrEmpty(ProxyAddress) || String.IsNullOrEmpty(ProxyProt))
            {
                return null;
            }
            return new WebProxy(ProxyAddress, Int16.Parse(ProxyProt));
        }

        private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
        /// <summary>
        /// 调用接口返回json数据（默认使用Get请求）
        /// </summary>
        /// <param name="reqJson"></param>
        /// <param name="Path"></param>
        /// <param name="respJson"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public static bool Response(String reqJson, String Path, out string respJson, EnumVerbs method = EnumVerbs.GET)
        {
            var Response = WebPost(Path, method, PubConstants.JSON, Encoding.GetEncoding((Int32)EnumCharsetType.UTF8).GetBytes(reqJson),
                EnumCharsetType.UTF8, PubConstants.RPCTimeout);
            respJson = Response.ResponseToString();
            return Response.Result;
        }


        /// <summary>
        /// web后台提交
        /// </summary>
        /// <param name="ActionURL">提交地址</param>
        /// <param name="ActionMethod">执行动作POST,GET</param>
        /// <param name="ContentType">参数格式</param>
        /// <param name="FormDataString">提交数据</param>
        /// <param name="Charset">FormData编码字符集及可以接收结果的字符编码集</param>
        /// <param name="RPCTimeout">执行超时时间(毫秒)</param>
        /// <param name="Cookies"></param>
        /// <returns>执行结果信息</returns>
        public static bool Response(string reqJson, out string respJson, String ActionURL, EnumVerbs ActionMethod, String ContentType,
            EnumCharsetType Charset, Int32 RPCTimeout, CookieCollection Cookies, Dictionary<string, string> Dic)
        {
            byte[] FormDataStr = null;
            if (!string.IsNullOrEmpty(reqJson))
                FormDataStr = Encoding.GetEncoding((Int32)Charset).GetBytes(reqJson);

            var Response = WebPost(ActionURL, ActionMethod, ContentType, FormDataStr, Charset, RPCTimeout, Cookies, Dic);
            respJson = Response.ResponseToString();
            return Response.Result;
        }

        public static T GetApiResultData<T, T1>(T respon, T1 request, string path)
            where T : class ,new()
            where T1 : class ,new()
        {
            var result = new T();
            try
            {
                var reqJson = request.T2Json();
                string respJson;
                var boolResult = Response(reqJson, path, out respJson);
                if (!boolResult)
                    return result;
                var resObj = respJson.Json2T<T>();
                return resObj;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }

    internal class AcceptAllCertificatePolicy : ICertificatePolicy
    {
        public bool CheckValidationResult(ServicePoint sPoint, X509Certificate cert, WebRequest wRequest, int certProb)
        {
            return true;
        }
    }
}
